/*
 * @Author: liusheng
 * @Date: 2022-04-21 10:38:23
 * @LastEditors: liusheng
 * @LastEditTime: 2022-06-19 19:48:49
 * @Description: 剑指 Offer II 037. 小行星碰撞
 * email:liusheng613@126.com
 * Copyright (c) 2022 by liusheng/liusheng, All Rights Reserved. 
 * 
 剑指 Offer II 037. 小行星碰撞
给定一个整数数组 asteroids，表示在同一行的小行星。

对于数组中的每一个元素，其绝对值表示小行星的大小，正负表示小行星的移动方向（正表示向右移动，负表示向左移动）。每一颗小行星以相同的速度移动。

找出碰撞后剩下的所有小行星。碰撞规则：两个行星相互碰撞，较小的行星会爆炸。如果两颗行星大小相同，则两颗行星都会爆炸。两颗移动方向相同的行星，永远不会发生碰撞。

 

示例 1：

输入：asteroids = [5,10,-5]
输出：[5,10]
解释：10 和 -5 碰撞后只剩下 10 。 5 和 10 永远不会发生碰撞。
示例 2：

输入：asteroids = [8,-8]
输出：[]
解释：8 和 -8 碰撞后，两者都发生爆炸。
示例 3：

输入：asteroids = [10,2,-5]
输出：[10]
解释：2 和 -5 发生碰撞后剩下 -5 。10 和 -5 发生碰撞后剩下 10 。
示例 4：

输入：asteroids = [-2,-1,1,2]
输出：[-2,-1,1,2]
解释：-2 和 -1 向左移动，而 1 和 2 向右移动。 由于移动方向相同的行星不会发生碰撞，所以最终没有行星发生碰撞。 
 

提示：

2 <= asteroids.length <= 104
-1000 <= asteroids[i] <= 1000
asteroids[i] != 0
 

注意：本题与主站 735 题相同： https://leetcode-cn.com/problems/asteroid-collision/
 */

#include "header.h"

//stack solution
//push the asteroids's value into stack,then process the stack
class Solution {
public:
    vector<int> asteroidCollision(vector<int>& asteroids) {
        stack<int> remainAsteroids;
        int n = asteroids.size();
        int i = 0;
        //operator with stack,should deal the stack element
        while (i < n)
        {
            //the condition to push the value
            /*几个条件只要满足一个就不会发生碰撞，可把当前行星压入栈：
            1.栈为空，不管当前行星是正是负(往左还是往右)都要压入栈；
            2.当前行星和栈顶行星同号说明同向移动不会碰撞；
            3.当前行星往右移动，栈顶行星向左移动也不会碰撞；*/
            if (remainAsteroids.empty() || remainAsteroids.top() < 0 || asteroids[i] > 0)
            {
                remainAsteroids.push(asteroids[i]);
            }
            //left is positive,right is negative
            //left move right,right move left
            else if (remainAsteroids.top() < -asteroids[i])
            {
                remainAsteroids.pop();
                continue;//no ++i,in next iterator the asteroids[i] will be compare to the new stack top
            }
            //remainAsteroids pop,++i
            else if (remainAsteroids.top() == -asteroids[i])
            {
                remainAsteroids.pop();
            }
            ++i;
        }

        int remainNum = remainAsteroids.size();
        if (remainNum == 0)
        {
            return {};
        }

        vector<int> asteroidLeft(remainNum);
        for (int i = remainNum - 1; i >= 0;--i)
        {
            asteroidLeft[i] = remainAsteroids.top();
            remainAsteroids.pop();
        }

        return asteroidLeft;
    }
};

class Solution2 {
public:
    vector<int> asteroidCollision(vector<int>& asteroids) {
        int n = asteroids.size();
        int i = 0;
        stack<int> remainAsteroids;
        while (i < n)
        {
            if (remainAsteroids.empty() || remainAsteroids.top() < 0 || asteroids[i] > 0)
            {
                remainAsteroids.push(asteroids[i]);
                ++i;
            }
            else if (remainAsteroids.top() < -asteroids[i])
            {
                //the stack top(left) was collisioned by the right
                // no ++i,compare the asteroids[i] with next top
                remainAsteroids.pop();
                continue;
            }
            else if (remainAsteroids.top() == -asteroids[i])
            {
                //collision both
                remainAsteroids.pop();
                ++i;
            }
            else 
            {
                ++i;//compare to next,asteroids[i] is collisioned by the stack top asteroid
            }
        }
        
        int remainNum = remainAsteroids.size();
        if (!remainNum)
        {
            return {};
        }
        
        vector<int> asteroidLeft(remainNum);
        for (int index = remainNum - 1; index >=0; --index)
        {
            asteroidLeft[index] = remainAsteroids.top();
            remainAsteroids.pop();
        }
        
        return asteroidLeft;
    }
};